#include<vector>
#include<ctime>
#include<cmath>
#include<string>
#include<fstream>
#include"Util.h"
#include"StringPool.h"
#include"variable.h"
#include"DependencyInstance.h"
#include"KBestParseForest.h"
#include"DependencyPipe3OTSibling.h"
using namespace std;

DependencyPipe3OTSibling::DependencyPipe3OTSibling(ParserOptions *options) : DependencyPipe2OSibling(options){}

DependencyPipe3OTSibling::~DependencyPipe3OTSibling(){}

void DependencyPipe3OTSibling::addExtendedFeatures(DependencyInstance *instance, FeatureVector *fv){
	const int instanceLength = instance->length();
	vector<int> *heads = instance->heads;

	// find all trip features
	for(int i = 0; i < instanceLength; i++){
		if((*heads)[i] == -1 && i != 0){
			continue;
		}

		// right children
		int prev = i;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				addTripFeatures(instance, i, prev, j, fv);
				addSiblingFeatures(instance, prev, j, prev == i, fv);
				prev = j;
			}
		}

		// left children
		prev = i;
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i){
				addTripFeatures(instance, i, prev, j, fv);
				addSiblingFeatures(instance, prev, j, prev == i, fv);
				prev = j;
			}
		}

		//right tri-sibling features
		prev = i;
		int nprev = i;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				addTriTripFeatures(instance, i, prev, nprev, j, fv);
				addTriSibFeatures(instance, prev, nprev, j, prev == i, fv);
				prev = nprev;
				nprev = j;
			}
		}

		//left tri-sibling features
		prev = i;
		nprev = i;
		for(int j = i - 1; j >= 0 ; j--){
			if((*heads)[j] == i){
				addTriTripFeatures(instance, i, prev, nprev, j, fv);
				addTriSibFeatures(instance, prev, nprev, j, prev == i, fv);
				prev = nprev;
				nprev = j;
			}
		}
	}
}

void DependencyPipe3OTSibling::addTriSibFeatures(DependencyInstance *instance, int ch1, int ch2, int ch3, bool isST, FeatureVector *fv){
	vector<string*> *pos = instance->postags;

	bool flag;
	string dir = ch1 > ch3 ? "RA" : "LA";

	string ch1_pos = isST ? "STPOS" : *(*pos)[ch1];
	string ch2_pos = ch2 == ch1 ? "STPOS" : *(*pos)[ch2];
	string ch3_pos = *(*pos)[ch3];

	vector<string*> *cpos = instance->cpostags;
	string ch1_cpos = isST ? "STCPOS" : *(*cpos)[ch1];
	string ch2_cpos = ch2 == ch1 ? "STCPOS" : *(*cpos)[ch2];
	string ch3_cpos = *(*cpos)[ch3];

	vector<string*> *forms = instance->forms;
	string ch1_form = isST ? "STWRD" : *(*forms)[ch1];
	string ch2_form = ch2 == ch1 ? "STWRD" : *(*forms)[ch2];
	string ch3_form = *(*forms)[ch3];

	string c1nt, c2nt, c3nt, c1nc, c2nc, c3nc;
	string c1pt, c2pt, c3pt, c1pc, c2pc, c3pc;

	if(ch1 > ch3){
		c1nt = (ch1 < instance->length() - 1) ? *(*pos)[ch1 + 1] : "EPOS";
		c1pt = (ch1 > ch2 + 1)                ? *(*pos)[ch1 - 1] : "MPOS";
		c2nt = (ch2 < ch1 - 1)                ? *(*pos)[ch2 + 1] : "MPOS";
		c2pt = (ch2 > ch3 + 1)                ? *(*pos)[ch2 - 1] : "MPOS";
		c3nt = (ch3 < ch2 - 1)                ? *(*pos)[ch3 + 1] : "MPOS";
		c3pt = (ch3 > 0)                      ? *(*pos)[ch3 - 1] : "SPOS";

		c1nc = (ch1 < instance->length() - 1) ? *(*cpos)[ch1 + 1] : "ECPOS";
		c1pc = (ch1 > ch2 + 1)                ? *(*cpos)[ch1 - 1] : "MCPOS";
		c2nc = (ch2 < ch1 - 1)                ? *(*cpos)[ch2 + 1] : "MCPOS";
		c2pc = (ch2 > ch3 + 1)                ? *(*cpos)[ch2 - 1] : "MCPOS";
		c3nc = (ch3 < ch2 - 1)                ? *(*cpos)[ch3 + 1] : "MCPOS";
		c3pc = (ch3 > 0)                      ? *(*cpos)[ch3 - 1] : "SCPOS";
	}
	else{
		c1nt = (ch1 < ch2 - 1)                ? *(*pos)[ch1 + 1] : "MPOS";
		c1pt = (ch1 > 0)                      ? *(*pos)[ch1 - 1] : "SPOS";
		c2nt = (ch2 < ch3 - 1)                ? *(*pos)[ch2 + 1] : "MPOS";
		c2pt = (ch2 > ch1 + 1)                ? *(*pos)[ch2 - 1] : "MPOS";
		c3nt = (ch3 < instance->length() - 1) ? *(*pos)[ch3 + 1] : "EPOS";
		c3pt = (ch3 > ch2 + 1)                ? *(*pos)[ch3 - 1] : "MPOS";

		c1nc = (ch1 < ch2 - 1)                ? *(*cpos)[ch1 + 1] : "MCPOS";
		c1pc = (ch1 > 0)                      ? *(*cpos)[ch1 - 1] : "SCPOS";
		c2nc = (ch2 < ch3 - 1)                ? *(*cpos)[ch2 + 1] : "MCPOS";
		c2pc = (ch2 > ch1 + 1)                ? *(*cpos)[ch2 - 1] : "MCPOS";
		c3nc = (ch3 < instance->length() - 1) ? *(*cpos)[ch3 + 1] : "ECPOS";
		c3pc = (ch3 > ch2 + 1)                ? *(*cpos)[ch3 - 1] : "MCPOS";
	}

	//Tri-Sibling
	string tSib_pos = ch1_pos + "_" + ch2_pos + "_" + ch3_pos;
	string tmp = "POS_TSIB=" + tSib_pos + "_" + dir;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "APOS_TSIB=" + tSib_pos;
	}
	else{
		tmp = "APOS_TSIB=" + tSib_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string tSib_cpos = ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos;
	tmp = "CPOS_TSIB=" + tSib_cpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "ACPOS_TSIB=" + tSib_cpos;
	}
	else{
		tmp = "ACPOS_TSIB=" + tSib_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	/* one form */
	string tSib_fpos = ch1_form + "_" + ch2_pos + "_" + ch3_pos;
	tmp = "FPOS1_TSIB=" + tSib_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOS1_TSIB=" + tSib_fpos;
	}
	else{
		tmp = "AFPOS1_TSIB=" + tSib_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string tSib_fcpos = ch1_form + "_" + ch2_cpos + "_" + ch3_cpos;
	tmp = "FCPOS1_TSIB=" + tSib_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOS1_TSIB=" + tSib_fcpos;
	}
	else{
		tmp = "AFCPOS1_TSIB=" + tSib_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fpos = ch1_pos + "_" + ch2_form + "_" + ch3_pos;
	tmp = "FPOS2_TSIB=" + tSib_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOS2_TSIB=" + tSib_fpos;
	}
	else{
		tmp = "AFPOS2_TSIB=" + tSib_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fcpos = ch1_cpos + "_" + ch2_form + "_" + ch3_cpos;
	tmp = "FCPOS2_TSIB=" + tSib_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOS2_TSIB=" + tSib_fcpos;
	}
	else{
		tmp = "AFCPOS2_TSIB=" + tSib_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fpos = ch1_pos + "_" + ch2_pos + "_" + ch3_form;
	tmp = "FPOS3_TSIB=" + tSib_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOS3_TSIB=" + tSib_fpos;
	}
	else{
		tmp = "AFPOS3_TSIB=" + tSib_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fcpos = ch1_cpos + "_" + ch2_cpos + "_" + ch3_form;
	tmp = "FCPOS3_TSIB=" + tSib_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOS3_TSIB=" + tSib_fcpos;
	}
	else{
		tmp = "AFCPOS3_TSIB=" + tSib_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	/* two forms */
	tSib_fpos = ch1_form + "_" + ch2_form + "_" + ch3_pos;
	tmp = "FPOS12_TSIB=" + tSib_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOS12_TSIB=" + tSib_fpos;
	}
	else{
		tmp = "AFPOS12_TSIB=" + tSib_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fcpos = ch1_form + "_" + ch2_form + "_" + ch3_cpos;
	tmp = "FCPOS12_TSIB=" + tSib_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOS12_TSIB=" + tSib_fcpos;
	}
	else{
		tmp = "AFCPOS12_TSIB=" + tSib_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fpos = ch1_form + "_" + ch2_pos + "_" + ch3_form;
	tmp = "FPOS13_TSIB=" + tSib_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOS13_TSIB=" + tSib_fpos;
	}
	else{
		tmp = "AFPOS13_TSIB=" + tSib_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fcpos = ch1_form + "_" + ch2_cpos + "_" + ch3_form;
	tmp = "FCPOS13_TSIB=" + tSib_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOS13_TSIB=" + tSib_fcpos;
	}
	else{
		tmp = "AFCPOS13_TSIB=" + tSib_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fpos = ch1_pos + "_" + ch2_form + "_" + ch3_form;
	tmp = "FPOS23_TSIB=" + tSib_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOS23_TSIB=" + tSib_fpos;
	}
	else{
		tmp = "AFPOS23_TSIB=" + tSib_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tSib_fcpos = ch1_cpos + "_" + ch2_form + "_" + ch3_form;
	tmp = "FCPOS23_TSIB=" + tSib_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOS23_TSIB=" + tSib_fcpos;
	}
	else{
		tmp = "AFCPOS23_TSIB=" + tSib_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	/* 3-gram context features */
	string context = ch1_pos + "_" + ch2_pos + "_" + ch3_pos + "_" + c1nt + "_" + c2nt + "_" + c3nt;
	tmp = "3GNPOS_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos + "_" + c1nc + "_" + c2nc + "_" + c3nc;
	tmp = "3GNCPOS_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch1_pos + "_" + ch2_pos + "_" + ch3_pos + "_" + c1pt + "_" + c2pt + "_" + c3pt;
	tmp = "3GPPOS_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos + "_" + c1pc + "_" + c2pc + "_" + c3pc;
	tmp = "3GPCPOS_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	/* 2-gram context features */
	context = ch1_pos + "_" + ch2_pos + "_" + c1nt + "_" + c2nt;
	tmp = "2GNPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch2_cpos + "_" + c1nc + "_" + c2nc;
	tmp = "2GNCPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch1_pos + "_" + ch2_pos + "_" + c1pt + "_" + c2pt;
	tmp = "2GPPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch2_cpos + "_" + c1pc + "_" + c2pc;
	tmp = "2GPCPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch1_pos + "_" + ch3_pos + "_" + c1nt + "_" + c3nt;
	tmp = "2GNPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch3_cpos + "_" + c1nc + "_" + c3nc;
	tmp = "2GNCPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch1_pos + "_" + ch3_pos + "_" + c1pt + "_" + c3pt;
	tmp = "2GPPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch1_cpos + "_" + ch3_cpos + "_" + c1pc + "_" + c3pc;
	tmp = "2GPCPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch2_pos + "_" + ch3_pos + "_" + c2nt + "_" + c3nt;
	tmp = "2GNPOS1_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch2_cpos + "_" + ch3_cpos + "_" + c2nc + "_" + c3nc;
	tmp = "2GNCPOS1_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = ch2_pos + "_" + ch3_pos + "_" + c2pt + "_" + c3pt;
	tmp = "2GPPOS1_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = ch2_cpos + "_" + ch3_cpos + "_" + c2pc + "_" + c3pc;
	tmp = "2GPCPOS1_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	
	//ch1-ch3
	tmp = "SCH_PAIR=" + ch1_pos + "_" + ch3_pos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_CPAIR=" + ch1_cpos + "_" + ch3_cpos + "_" + dir;
	}
	else{
		tmp = "SCH_CPAIR=" + ch1_cpos + "_" + ch3_cpos + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_WPAIR=" + ch1_form + "_" + ch3_form + "_" + dir;
	}
	else{
		tmp = "SCH_WPAIR=" + ch1_form + "_" + ch3_form + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_WPAIRA=" + ch1_form + "_" + ch3_pos + "_" + dir;
	}
	else{
		tmp = "SCH_WPAIRA=" + ch1_form + "_" + ch3_pos + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_WPAIRB=" + ch1_pos + "_" + ch3_form + "_" + dir;
	}
	else{
		tmp = "SCH_WPAIRB=" + ch1_pos + "_" + ch3_form + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_WPAIRC=" + ch1_form + "_" + ch3_cpos + "_" + dir;
	}
	else{
		tmp = "SCH_WPAIRC=" + ch1_form + "_" + ch3_cpos + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_WPAIRD=" + ch1_cpos + "_" + ch3_form + "_" + dir;
	}
	else{
		tmp = "SCH_WPAIRD=" + ch1_cpos + "_" + ch3_form + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_PAIR=" + ch1_pos + "_" + ch3_pos;
	}
	else{
		tmp = "ASCH_PAIR=" + ch1_pos + "_" + ch3_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_CPAIR=" + ch1_cpos + "_" + ch3_cpos;
	}
	else{
		tmp = "ASCH_CPAIR=" + ch1_cpos + "_" + ch3_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_WPAIR=" + ch1_form + "_" + ch3_form;
	}
	else{
		tmp = "ASCH_WPAIR=" + ch1_form + "_" + ch3_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_WPAIRA=" + ch1_form + "_" + ch3_pos;
	}
	else{
		tmp = "ASCH_WPAIRA=" + ch1_form + "_" + ch3_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_WPAIRB=" + ch1_pos + "_" + ch3_form;
	}
	else{
		tmp = "ASCH_WPAIRB=" + ch1_pos + "_" + ch3_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_WPAIRC=" + ch1_form + "_" + ch3_cpos;
	}
	else{
		tmp = "ASCH_WPAIRC=" + ch1_form + "_" + ch3_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_WPAIRD=" + ch1_cpos + "_" + ch3_form;
	}
	else{
		tmp = "ASCH_WPAIRD=" + ch1_cpos + "_" + ch3_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	int dist = abs(ch1 - ch3);
	string distBool = "0";
	if (dist > 1){
		distBool = "1";
	}
	if (dist > 2){
		distBool = "2";
	}
	if (dist > 3){
		distBool = "3";
	}
	if (dist > 4){
		distBool = "4";
	}
	if (dist > 5){
		distBool = "5";
	}
	if (dist > 10){
		distBool = "10";
	}

	tmp = "SCH_PAIR_DIST=" + distBool + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_PAIR_DIST=" + distBool;
	}
	else{
		tmp = "ASCH_PAIR_DIST=" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_PAIR_DIST=" + ch1_pos + "_" + ch3_pos + "_" + distBool + "_" + dir;
	}
	else{
		tmp = "SCH_PAIR_DIST=" + ch1_pos + "_" + ch3_pos + "_" + distBool + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_PAIR_DIST=" + ch1_pos + "_" + ch3_pos + "_" + distBool;
	}
	else{
		tmp = "ASCH_PAIR_DIST=" + ch1_pos + "_" + ch3_pos + "_" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "SCH_CPAIR_DIST=" + ch1_cpos + "_" + ch3_cpos + "_" + distBool + "_" + dir;
	}
	else{
		tmp = "SCH_CPAIR_DIST=" + ch1_cpos + "_" + ch3_cpos + "_" + distBool + "_" + dir;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "ASCH_CPAIR_DIST=" + ch1_cpos + "_" + ch3_cpos + "_" + distBool;
	}
	else{
		tmp = "ASCH_CPAIR_DIST=" + ch1_cpos + "_" + ch3_cpos + "_" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe3OTSibling::addTriTripFeatures(DependencyInstance *instance, int par, int ch1, int ch2, int ch3, FeatureVector *fv){
	vector<string*> *pos = instance->postags;

	bool flag;
	string dir = par > ch3 ? "RA" : "LA";

	string par_pos = *(*pos)[par];
	string ch1_pos = ch1 == par ? "STPOS" : *(*pos)[ch1];
	string ch2_pos = ch2 == par ? "STPOS" : *(*pos)[ch2];
	string ch3_pos = *(*pos)[ch3];

	vector<string*> *cpos = instance->cpostags;
	string par_cpos = *(*cpos)[par];
	string ch1_cpos = ch1 == par ? "STCPOS" : *(*cpos)[ch1];
	string ch2_cpos = ch2 == par ? "STCPOS" : *(*cpos)[ch2];
	string ch3_cpos = *(*cpos)[ch3];

	vector<string*> *forms = instance->forms;
	string par_form = *(*forms)[par];
	string ch1_form = ch1 == par ? "STWRD" : *(*forms)[ch1];
	string ch2_form = ch2 == par ? "STWRD" : *(*forms)[ch2];
	string ch3_form = *(*forms)[ch3];

	string pnt, c1nt, c2nt, c3nt, pnc, c1nc, c2nc, c3nc;
	string ppt, c1pt, c2pt, c3pt, ppc, c1pc, c2pc, c3pc;

	if(par > ch3){
		pnt  = (par < instance->length() - 1) ? *(*pos)[par + 1] : "EPOS";
		ppt  = (par > ch1 + 1)                ? *(*pos)[par - 1] : "MPOS";
		c1nt = (ch1 < par - 1)                ? *(*pos)[ch1 + 1] : "MPOS";
		c1pt = (ch1 > ch2 + 1)                ? *(*pos)[ch1 - 1] : "MPOS";
		c2nt = (ch2 < ch1 - 1)                ? *(*pos)[ch2 + 1] : "MPOS";
		c2pt = (ch2 > ch3 + 1)                ? *(*pos)[ch2 - 1] : "MPOS";
		c3nt = (ch3 < ch2 - 1)                ? *(*pos)[ch3 + 1] : "MPOS";
		c3pt = (ch3 > 0)                      ? *(*pos)[ch3 - 1] : "SPOS";

		pnc  = (par < instance->length() - 1) ? *(*cpos)[par + 1] : "ECPOS";
		ppc  = (par > ch1 + 1)                ? *(*cpos)[par - 1] : "MCPOS";
		c1nc = (ch1 < par - 1)                ? *(*cpos)[ch1 + 1] : "MCPOS";
		c1pc = (ch1 > ch2 + 1)                ? *(*cpos)[ch1 - 1] : "MCPOS";
		c2nc = (ch2 < ch1 - 1)                ? *(*cpos)[ch2 + 1] : "MCPOS";
		c2pc = (ch2 > ch3 + 1)                ? *(*cpos)[ch2 - 1] : "MCPOS";
		c3nc = (ch3 < ch2 - 1)                ? *(*cpos)[ch3 + 1] : "MCPOS";
		c3pc = (ch3 > 0)                      ? *(*cpos)[ch3 - 1] : "SCPOS";
	}
	else{
		pnt  = (par < ch1 - 1)                ? *(*pos)[par + 1] : "MPOS";
		ppt  = (par > 0)                      ? *(*pos)[par - 1] : "SPOS";
		c1nt = (ch1 < ch2 - 1)                ? *(*pos)[ch1 + 1] : "MPOS";
		c1pt = (ch1 > par + 1)                ? *(*pos)[ch1 - 1] : "MPOS";
		c2nt = (ch2 < ch3 - 1)                ? *(*pos)[ch2 + 1] : "MPOS";
		c2pt = (ch2 > ch1 + 1)                ? *(*pos)[ch2 - 1] : "MPOS";
		c3nt = (ch3 < instance->length() - 1) ? *(*pos)[ch3 + 1] : "EPOS";
		c3pt = (ch3 > ch2 + 1)                ? *(*pos)[ch3 - 1] : "MPOS";

		pnc  = (par < ch1 - 1)                ? *(*cpos)[par + 1] : "MCPOS";
		ppc  = (par > 0)                      ? *(*cpos)[par - 1] : "SCPOS";
		c1nc = (ch1 < ch2 - 1)                ? *(*cpos)[ch1 + 1] : "MCPOS";
		c1pc = (ch1 > par + 1)                ? *(*cpos)[ch1 - 1] : "MCPOS";
		c2nc = (ch2 < ch3 - 1)                ? *(*cpos)[ch2 + 1] : "MCPOS";
		c2pc = (ch2 > ch1 + 1)                ? *(*cpos)[ch2 - 1] : "MCPOS";
		c3nc = (ch3 < instance->length() - 1) ? *(*cpos)[ch3 + 1] : "ECPOS";
		c3pc = (ch3 > ch2 + 1)                ? *(*cpos)[ch3 - 1] : "MCPOS";
	}

	//Tri-Trip
	string tTrip_pos = par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_pos;
	string tmp = "POS_TTRIP=" + tTrip_pos + "_" +dir;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "APOS_TTRIP=" + tTrip_pos;
	}
	else{
		tmp = "APOS_TTRIP=" + tTrip_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string tTrip_cpos = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos;
	tmp = "CPOS_TTRIP=" + tTrip_cpos + "_" +dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "ACPOS_TTRIP=" + tTrip_cpos;
	}
	else{
		tmp = "ACPOS_TTRIP=" + tTrip_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string tTrip_fpos = par_form + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_pos;
	tmp = "FPOSP_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSP_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSP_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string tTrip_fcpos = par_form + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos;
	tmp = "FCPOSP_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSP_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSP_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_pos + "_" + ch1_form + "_" + ch2_pos + "_" + ch3_pos;
	tmp = "FPOSC1_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSC1_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSC1_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_cpos + "_" + ch1_form + "_" + ch2_cpos + "_" + ch3_cpos;
	tmp = "FCPOSC1_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSC1_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSC1_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_pos + "_" + ch1_pos + "_" + ch2_form + "_" + ch3_pos;
	tmp = "FPOSC2_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSC2_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSC2_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_cpos + "_" + ch1_cpos + "_" + ch2_form + "_" + ch3_cpos;
	tmp = "FCPOSC2_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSC2_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSC2_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_form;
	tmp = "FPOSC3_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSC3_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSC3_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_form;
	tmp = "FCPOSC3_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSC3_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSC3_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_form + "_" + ch1_form + "_" + ch2_pos + "_" + ch3_pos;
	tmp = "FPOSPC1_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSPC1_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSPC1_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_form + "_" + ch1_form + "_" + ch2_cpos + "_" + ch3_cpos;
	tmp = "FCPOSPC1_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSPC1_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSPC1_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_form + "_" + ch1_pos + "_" + ch2_form + "_" + ch3_pos;
	tmp = "FPOSPC2_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSPC2_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSPC2_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_form + "_" + ch1_cpos + "_" + ch2_form + "_" + ch3_cpos;
	tmp = "FCPOSPC2_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSPC2_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSPC2_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_form + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_form;
	tmp = "FPOSPC3_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSPC3_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSPC3_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_form + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_form;
	tmp = "FCPOSPC3_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSPC3_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSPC3_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_pos + "_" + ch1_form + "_" + ch2_form + "_" + ch3_pos;
	tmp = "FPOSC12_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSC12_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSC12_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_cpos + "_" + ch1_form + "_" + ch2_form + "_" + ch3_cpos;
	tmp = "FCPOSC12_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSC12_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSC12_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_pos + "_" + ch1_form + "_" + ch2_pos + "_" + ch3_form;
	tmp = "FPOSC13_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSC13_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSC13_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_cpos + "_" + ch1_form + "_" + ch2_cpos + "_" + ch3_form;
	tmp = "FCPOSC13_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSC13_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSC13_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fpos = par_pos + "_" + ch1_pos + "_" + ch2_form + "_" + ch3_form;
	tmp = "FPOSC23_TTRIP=" + tTrip_fpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFPOSC23_TTRIP=" + tTrip_fpos;
	}
	else{
		tmp = "AFPOSC23_TTRIP=" + tTrip_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	tTrip_fcpos = par_cpos + "_" + ch1_cpos + "_" + ch2_form + "_" + ch3_form;
	tmp = "FCPOSC23_TTRIP=" + tTrip_fcpos + "_" + dir;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFCPOSC23_TTRIP=" + tTrip_fcpos;
	}
	else{
		tmp = "AFCPOSC23_TTRIP=" + tTrip_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//context features
	/* 4-gram context features */
	string context = par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_pos + "_" + pnt + "_" + c1nt + "_" + c3nt;
	tmp = "4GNPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos + "_" + pnc + "_" + c1nc + "_" + c3nc;
	tmp = "4GNCPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_pos + "_" + ppt + "_" + c1pt + "_" + c3pt;
	tmp = "4GPPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos + "_" + ppc + "_" + c1pc + "_" + c3pc;
	tmp = "4GPCPOS3_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_pos + "_" + pnt + "_" + c1nt;
	tmp = "4GNPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos + "_" + pnc + "_" + c1nc;
	tmp = "4GNCPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	context = par_pos + "_" + ch1_pos + "_" + ch2_pos + "_" + ch3_pos + "_" + ppt + "_" + c1pt;
	tmp = "4GPPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
	context = par_cpos + "_" + ch1_cpos + "_" + ch2_cpos + "_" + ch3_cpos + "_" + ppc + "_" + c1pc;
	tmp = "4GPCPOS2_CNT=" + context;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe3OTSibling::writeExtendedFeatures(DependencyInstance *instance, ObjectWriter &out){
	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector prodFV = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector prodFV = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}

	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = 0; w2 <instanceLength; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					FeatureVector prodFV = FeatureVector();
					addSiblingFeatures(instance, w1, w2, wh == 0, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
				}
			}
		}
	}

	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			int s = (w2 == w1) ? w2 : w2 + 1;
			for(int w3 = s; w3 < instanceLength; w3++){
				for(int w4 = w3 + 1; w4 < instanceLength; w4++){
					FeatureVector prodFV = FeatureVector();
					addTriTripFeatures(instance, w1, w2, w3, w4, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
				}
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			int s = (w2 == w1) ? w2 : w2 - 1;
			for(int w3 = s; w3 >= 0; w3--){
				for(int w4 = w3 - 1; w4 >= 0; w4--){
					FeatureVector prodFV = FeatureVector();
					addTriTripFeatures(instance, w1, w2, w3, w4, &prodFV);
					int *keys = prodFV.keys();
					out.writeArray(keys, (int)(prodFV.size()));
					delete[](keys);
				}
			}
		}
	}
	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				for(int wh = 0; wh < 2; wh++){
					if(!(wh == 1 && w1 == w2)){
						FeatureVector prodFV = FeatureVector();
						addTriSibFeatures(instance, w1, w2, w3, wh == 0, &prodFV);
						int *keys = prodFV.keys();
						out.writeArray(keys, (int)(prodFV.size()));
						delete[](keys);
					}
				}
			}
		}

		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					if(!(wh == 1 && w1 == w2)){
						FeatureVector prodFV = FeatureVector();
						addTriSibFeatures(instance, w1, w2, w3, wh == 0, &prodFV);
						int *keys = prodFV.keys();
						out.writeArray(keys, (int)(prodFV.size()));
						delete[](keys);
					}
				}
			}
		}
	}
	out.writeInt(-3);
}

DependencyInstance* DependencyPipe3OTSibling::readInstance(ObjectReader &in, int length, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_trips, std::vector<vector<vector<double> > > &probs_sibs, std::vector<vector<vector<vector<double> > > > &probs_ttrips, std::vector<vector<vector<vector<double> > > > &probs_tsibs, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	// Get production crap.
	for (int w1 = 0; w1 < length; w1++) {
		for (int w2 = w1 + 1; w2 < length; w2++) {
			for (int ph = 0; ph < 2; ph++) {
				int *keys = NULL;
				int size = in.readArray(keys);
				probs[w1][w2][ph] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	int last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	if (labeled) {
		for (int w1 = 0; w1 < length; w1++) {
			int len = (int)(types.size());
			for (int t = 0; t < len; t++) {
				for (int ph = 0; ph < 2; ph++) {
					for (int ch = 0; ch < 2; ch++) {
						int *keys = NULL;
						int size = in.readArray(keys);
						nt_probs[w1][t][ph][ch] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}
		last = in.readInt();
		if (last != -3) {
			cout<<"Error reading file."<<endl;
			exit(0);
		}
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_trips[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				int *keys = NULL;
				int size = in.readArray(keys);
				probs_trips[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = 0; w2 <length; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_sibs[w1][w2][wh] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1; w2 < length; w2++){
			int s = (w2 == w1) ? w2 : w2 + 1;
			for(int w3 = s; w3 < length; w3++){
				for(int w4 = w3 + 1; w4 < length; w4++){
					int w3_fin = (w2 == w1 ? w3 : w3 - w2 - 1);
					int w4_fin = ((w2 == w1 && w3 == w2) ? w4 : w4 - w3 - 1);
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_ttrips[w1][w2][w3_fin][w4_fin] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}
		for(int w2 = w1; w2 >= 0 ; w2--){
			int s = (w2 == w1) ? w2 : w2 - 1;
			for(int w3 = s; w3 >= 0; w3--){
				for(int w4 = w3 - 1; w4 >= 0; w4--){
					int *keys = NULL;
					int size = in.readArray(keys);
					probs_ttrips[w1][w2][w3][w4] = getScore(params->parameters, keys, size);
					delete[](keys);
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				for(int wh = 0; wh < 2; wh++){
					if(!(wh == 1 && w1 == w2)){
						int *keys = NULL;
						int size = in.readArray(keys);
						int w3_fin = (w2 == w1 ? w3 : w3 - w2 - 1);
						probs_tsibs[w1][w2][w3_fin][wh] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}

		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					if(!(wh == 1 && w1 == w2)){
						int *keys = NULL;
						int size = in.readArray(keys);
						probs_tsibs[w1][w2][w3][wh] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	int *keys = NULL;
	int size = in.readArray(keys);
	FeatureVector* nfv = new FeatureVector();
	nfv->construct(keys, size);
	delete[](keys);
	last = in.readInt();
	if (last != -4) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	DependencyInstance* marshalledDI = new DependencyInstance();
	marshalledDI->readObject(in);
	marshalledDI->setFeatureVector(nfv);

	last = in.readInt();
	if (last != -1) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}
	return marshalledDI;
}

void  DependencyPipe3OTSibling::fillFeatureVectors(DependencyInstance *instance, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_trips, std::vector<vector<vector<double> > > &probs_sibs, std::vector<vector<vector<vector<double> > > > &probs_ttrips, vector<vector<vector<vector<double> > > > &probs_tsibs, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	((DependencyPipe*)this)->fillFeatureVectors(instance, probs, nt_probs, params);

	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				FeatureVector fv = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_trips[w1][w2][w3] = prodProb;
			}
		}
		for(int w2 = w1; w2 >= 0 ; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				FeatureVector fv = FeatureVector();
				addTripFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_trips[w1][w2][w3] = prodProb;
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = 0; w2 <instanceLength; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					FeatureVector fv = FeatureVector();
					addSiblingFeatures(instance, w1, w2, wh == 0, &fv);
					double prodProb = params->getScore(&fv);
					probs_sibs[w1][w2][wh] = prodProb;
				}
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			int s = (w2 == w1) ? w2 : w2 + 1;
			for(int w3 = s; w3 < instanceLength; w3++){
				for(int w4 = w3 + 1; w4 < instanceLength; w4++){
					int w3_fin = (w2 == w1 ? w3 : w3 - w2 - 1);
					int w4_fin = ((w2 == w1 && w3 == w2) ? w4 : w4 - w3 - 1);
					FeatureVector fv = FeatureVector();
					addTriTripFeatures(instance, w1, w2, w3, w4, &fv);
					double prodProb = params->getScore(&fv);
					probs_ttrips[w1][w2][w3_fin][w4_fin] = prodProb;
				}
			}
		}
		for(int w2 = w1; w2 >= 0 ; w2--){
			int s = (w2 == w1) ? w2 : w2 - 1;
			for(int w3 = s; w3 >= 0; w3--){
				for(int w4 = w3 - 1; w4 >= 0; w4--){
					FeatureVector fv = FeatureVector();
					addTriTripFeatures(instance, w1, w2, w3, w4, &fv);
					double prodProb = params->getScore(&fv);
					probs_ttrips[w1][w2][w3][w4] = prodProb;
				}
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1; w2 < instanceLength; w2++){
			for(int w3 = w2 + 1; w3 < instanceLength; w3++){
				for(int wh = 0; wh < 2; wh++){
					if(!(wh == 1 && w1 == w2)){
						int w3_fin = (w2 == w1 ? w3 : w3 - w2 - 1);
						FeatureVector fv = FeatureVector();
						addTriSibFeatures(instance, w1, w2, w3, wh == 0, &fv);
						double prodProb = params->getScore(&fv);
						probs_tsibs[w1][w2][w3_fin][wh] = prodProb;
					}
				}
			}
		}

		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					if(!(wh == 1 && w1 == w2)){
						FeatureVector fv = FeatureVector();
						addTriSibFeatures(instance, w1, w2, w3, wh == 0, &fv);
						double prodProb = params->getScore(&fv);
						probs_tsibs[w1][w2][w3][wh] = prodProb;
					}
				}
			}
		}
	}
}